from driver import UART
from driver import ADC
import utime as time
import uos
import ujson
# import _thread
import hmibase
import ubinascii
import ustruct
import power
import app_relay
import app_config
# import sleep_mode


class HmiDrver(object):
    def __init__(self,port="rs232",buffer_size=50):
        self.uart_hmi = UART()
        self.uart_hmi.open(port)
        self.uart_hmi.on(self.recive_from_hmi)
        #电源电压
        self.adc1Obj = ADC()
        self.adc1Obj.open('adc1')

        #标志位
        self.receiveing = False
        self.collect_flag = True      # 切换自动采集和软件连接的标志位
        self.recieve_data = None
        #回调函数
        self.hmi_hander = None  # 读取传感器 回调
        self.RTCcalback = None  # RTC 回调
        # TF卡变量
        self.tf_file_path = '/sdcard0/'
        self.TfObj  = None
    
          
        self.interval = 0  # 采集时间间隔
      
        # 日期时间变量
        self.time_list = {'year':2024,'month':12,'day':1,'hour':0,
                       'minute':0,'second':0,'week':1}  # 时间列表      
        # 数据帧变量
        self.frames =[]            # 接收数据帧
        self.cmd_head = ''         # 帧头
        self.cmd_type = ''         # 命令类型(UPDATE_CONTROL)
        self.ctrl_msg = ''         # CtrlMsgType-指示消息的类型
        self.screen_id = ''        # 产生消息的画面ID
        self.control_id = ''       # 产生消息的控件ID
        self.control_type = ''     # 控件类型
        self.param = ''            # 可变长度参数
        self.cmd_tail = ''         # 帧尾

        # self.display_run()      # 这里不开启UI更新线程
   

    def rtc_set(self,datatime):
        second = str(datatime[5])
        minute = str(datatime[4])
        hour = str(datatime[3])
        day = str(datatime[2])
        weekend = str(datatime[6])
        morth = str(datatime[1])
        year = str(datatime[0]-2000)
        cmd = hmibase.BEGIN_CMD()
        cmd += hmibase.TX_8(0x81)
        cmd+= hmibase.TX_8(second)
        cmd+=hmibase.TX_8(minute)
        cmd+=hmibase.TX_8(hour)
        cmd+=hmibase.TX_8(day)
        cmd+=hmibase.TX_8(weekend)
        cmd+=hmibase.TX_8(morth)
        cmd += hmibase.TX_8(year)
        cmd += hmibase.END_CMD()
        self.uart_hmi.write(cmd)
             
    def read_recive_data(self,data):
        """
        brief: 获取串口屏数据帧
        return: 返回最后一帧数据
        """
        data_head = "ee"
        data_end = "fffcffff"
        hand_index = 0
        size = len(data)
        # 二进制字节串转16进制再解码为字符串
        datastr = ubinascii.hexlify(data).decode('utf-8')
        # print(datastr)
        # print(size)
        # 寻找所有的帧数据
        while size > 0:
            # 寻找帧头
            hand_index = datastr.find(data_head,hand_index)
            if hand_index == -1:
                break
            # 寻找帧尾
            end_index = datastr.find(data_end,hand_index)
            if end_index == -1:
                break
            end_index += len(data_end)
            frame  = datastr[hand_index:end_index]
            self.frames.append(frame)
            hand_index = end_index 
            # print(hand_index)
        if self.frames:
            # 获取最后一个帧
            last_frame = self.frames[-1]
            self.frames= []                 # 清空当前阵列表以准备下一次读取
            # print(last_frame)
            return last_frame
        else:
            return None

    # def display_run(self):
    #     _thread.start_new_thread(self.display_thread,())   
    # def display_thread(self):        
    #     while True:
    #         if not self.collect_flag :
    #             try:
    #                 time.sleep(0.5)
    #                 self.UpdataUI()
    #             except Exception as e:
    #                 print("display thread error:",e)
    #             time.sleep(1)
                                                    
    #         else:
    #             time.sleep(1)

    def recive_from_hmi(self,recdata):  
        
        data = self.read_recive_data(recdata)    # 获取串口屏数据
        if data:
            # print('recive data:',data)
            self.pare_cmd_from_buffer(data)
            self.process_message()  

    def pare_cmd_from_buffer(self,dataframe):
        """
        brief: 解析数据帧
        """
        self.cmd_head = dataframe[:2]              # 帧头   半个字节
        self.cmd_type = dataframe[2:4]             # 命令类型(UPDATE_CONTROL)如，0xB1
        self.ctrl_msg = dataframe[4:6]             # 指示消息的类型,如，0x11发送mcu或者0x10接收mcu信息
        self.screen_id = dataframe[6:10]           # 产生消息的画面ID
        self.control_id = dataframe[10:14]           # 产生消息的控件ID  1bytes
        self.control_type = dataframe[14:16]         # 控件类型 如，0x10为按钮
        self.param = dataframe[16:-8]                # 可变长度参数
        self.cmd_tail = dataframe[-8:]               # 帧尾

      # 信息处理流程  
    def process_message(self):
        control_type = {
            '10' : self.NotifyButton,  # 按钮
            '11' : self.NotifyText,    # 文本
            '1b' : self.NotifySelector,  # 选择控件
            '13' : self.NotifySlider    # 滑块   
        }
        # print(self.cmd_type)
        if self.cmd_type == "b1":
            handler = control_type.get(self.control_type)
            if handler:
                handler(self.screen_id,self.control_id,self.param)
            else:
                print("Unknown control type")
        elif self.cmd_type == 'f7':
              self.set_rtc_from_hmi()
              
        else:
            return

                         
    def set_rtc_from_hmi(self):
        '''
        brief: 从显示屏设置的时间中获取RTC时间
        '''
        get_rtc = (self.ctrl_msg + self.screen_id + self.control_id 
        +self.control_type +self.param )
        year = int(get_rtc[0:2])  
        month = int(get_rtc[2:4])  
        week = int(get_rtc[4:6])   
        day = int(get_rtc[6:8])     
        hour = int(get_rtc[8:10])   
        minute = int(get_rtc[10:12]) 
        second = int(get_rtc[12:14])
        # 设置校准标志位
        if self.RTCcalback:
            self.RTCcalback(year=(2000+year),month=month,day=day,hour=hour,minute=minute,second=second)


    def read_rtc_from_dev(self):
        '''
        brief: 读取RTC时间
        '''
        if self.RTCcalback:
            try:
                # 获取当前RTC时间
                data_time = self.RTCcalback()
                if data_time is not None and isinstance(data_time, str):
                    # print('time',data_time)
                    self.SetTextValue(0,0,data_time)           
            except Exception as e:
                # self.SetTextValue(0,0,'RTCError')
                print("Error getting RTC time:", e)
        
        
    def NotifyButton(self,screen_id, control_id,state):
        '''
          brief  按钮控件通知  
          details  当按钮状态改变，执行此函数
          param screen_id 画面ID
          param control_id 控件ID
          param state 按钮状态:0 弹起,1按下
        '''
        screen_id = screen_id[-2:]
        control_id = control_id[-2:]
        # print(screen_id,control_id)
        if screen_id == '00' and control_id == '1f':
            # self.ReadRTC() 
            # self.collect_flag = True  
            print("start logging")
        if screen_id == '00' and control_id == '20':
            # self.collect_flag = False 
            print("stop logging")
            
        if screen_id == '00' and control_id == '16':
            self.ReadRTC() 

    def NotifyText(self,screen_id, control_id,text):
        '''
          brief  文本控件通知  
          details  当文本通过屏幕按键更新，执行此函数
          param screen_id 画面ID
          param control_id 控件ID
          param  text     文本内容
        '''
        screen_id = screen_id[-2:]
        control_id = control_id[-2:]
        if screen_id == '00' and control_id == '12':
            try:
                ascii_string = ubinascii.unhexlify(text).decode('utf-8').split('\0')   # 将16进制转字节串再转字符串
                # print("ascii_string:",ascii_string) #ascii_string: ['001000', '']
                interval = ascii_string[0]
                # 保存到文件
                if app_config.write_interval_to_config(int(interval)):
                    self.interval = int(interval)
                else:
                    self.interval = 300
            except Exception as e:
                print("Failed to update interval:",e)


        if screen_id == '00' and control_id == '13':
             ascii_string = ubinascii.unhexlify(text).decode('utf-8').split('\0')
             tf_file_str= ascii_string[0]
             filename = self.tf_file_path + tf_file_str
             self.send_data(filename)
            
        if screen_id == '00' and control_id == '14':
            ascii_string = ubinascii.unhexlify(text).decode('utf-8').split('\0')
            del_tf_file_str= ascii_string[0]
            pass
            

        if screen_id == '00' and control_id == '15':
            ascii_string = ubinascii.unhexlify(text).decode('utf-8').split('\0')
            pass
            
            

    def NotifySelector(self,screen_id,control_id, item):
        ''' 
        *  \brief  滑动选择控件通知
        *  \param screen_id 画面ID
        *  \param control_id 控件ID
        *  \param item 当前列表索引值
        '''
        screen_id = screen_id[-2:]
        control_id = control_id[-2:]
        if(screen_id == '00' and control_id == '0c'): 
            pass
    
    def NotifySlider(self,screen_id, control_id,value):
        '''                                                                            
          brief  滑动条控件通知                                                                      
          param screen_id 画面ID                                                      
          param control_id 控件ID                                                     
          param value 值                                                              
        '''
        self.current_screen_id = screen_id
        self.control_id = control_id
        self.value = value

    def SetTextFloat(self,screen_id, control_id, floatvalue, precision):
        '''
          brief   设置文本单精度浮点值 
          param  screen_id 画面ID
          param  control_id 控件ID
          param  floatvalue 浮点数值
          param  precision 小数位数，若不够则末尾补零
        '''
        cmd = hmibase.BEGIN_CMD()
        cmd += hmibase.TX_8(0xB1)
        cmd += hmibase.TX_8(0x07)
        cmd += hmibase.TX_16(screen_id)
        cmd += hmibase.TX_16(control_id)
        cmd += hmibase.TX_8(0x02)
        cmd += hmibase.TX_8((precision &0x0F) | 0x80 )
        # 将float值转换为字节，并处理大小端 ,这里我们使用大端格式 '>f'，如果需要小端格式，可以使用 '<f'
        float_bytes = ustruct.pack('>f',floatvalue) 
        # 使用大端格式 
        cmd += float_bytes 
        cmd += hmibase.END_CMD()
        # print(cmd)
        self.uart_hmi.write(cmd)
    # 发送字节类型
    def SetTextInt32(self,screen_id, control_id,value,sign,fill_zero):
        ''' 
            brief  设置文本为整数值
            param  screen_id 画面ID
            param  control_id 控件ID
            param  value 文本数值
            param  sign 0-无符号,1-有符号
            param  fill_zero 位数，不足时左侧补零
        '''
        cmd = hmibase.BEGIN_CMD()
        cmd += hmibase.TX_8(0xB1)
        cmd += hmibase.TX_8(0x07)
        cmd += hmibase.TX_16(screen_id)
        cmd += hmibase.TX_16(control_id)
        cmd += hmibase.TX_8(0x01 if sign else 0x00)
        cmd += hmibase.TX_8((fill_zero & 0x0F) | 0x80)
        cmd += hmibase.TX_32(value)
        cmd += hmibase.END_CMD()
        # print(cmd)
        self.uart_hmi.write(cmd)

    def SetTextValue(self,screen_id,control_id,str):
        '''
          brief     设置文本值
          param  screen_id 画面ID
          param  control_id 控件ID
          param  str 文本值(字符串)
        '''
        cmd = hmibase.BEGIN_CMD()
        cmd += hmibase.TX_8(0xB1)
        cmd += hmibase.TX_8(0x10)
        cmd += hmibase.TX_16(screen_id)
        cmd += hmibase.TX_16(control_id)
        cmd += hmibase.SendStrings(str)
        cmd += hmibase.END_CMD()
        self.uart_hmi.write(cmd)

    

    def ReadRTC(self):
        '''
        brief: 读取屏幕的RTC时间,屏幕返回时间数据
        '''
        cmd = hmibase.BEGIN_CMD()
        cmd += hmibase.TX_8((0x2 & 0x0F) | 0x80)
        cmd += hmibase.END_CMD()
        self.uart_hmi.write(cmd)

    def register_calback(self,handler):
        '''
        brief: 注册回调函数
        '''
        if handler:
            self.hmi_hander = handler
        else:
            print("time data handler is None")

    def register_rtc_calback(self,handler):
        '''
        brief: 注册触摸屏RTC回调函数,读取触摸屏时间到系统RTC
        '''
        if handler:
            self.RTCcalback = handler
        else:
            print('RTC RtChandler is None')
        
        # 获取当前采集间隔
    def get_interval(self):
        return self.interval

    def get_collect_flag(self):
        return self.collect_flag

    def set_collect_flag(self,flag:bool):
        if flag:
            self.collect_flag = True
        else:
            self.collect_flag = False

   # UI更新
    def UpdataUI(self):
        try:
            if self.hmi_hander and app_relay.get_relay_state(1) == 1:
                self.recieve_data = self.hmi_hander()
                if self.recieve_data :
                    # self.SetTextFloat(0,1,self.recieve_data['voltage_485RS'][0]*800,0,1)
                    # self.SetTextInt32(0,2,self.recieve_data['temp'][0],0,1)
                    # self.SetTextInt32(0,3,self.recieve_data['temp'][1],0,1)
                    power_votage=float(power.power_votage())
                    self.SetTextFloat(0,3,power_votage,3) 
                else:
                    # print("no data")
                    return False
            else:
                return  

        except Exception as e:
            print("updata ui error:",e)
            return

    
     
    
    

   